package com.googlecode.jawb;

import java.nio.ByteBuffer;

/**
 * Workaround for operations with Java primitive types. 
 */
public enum Type {
	/** Not a Java primitive type. */
	NONE(new Class<?>[]{}) {
		@Override
		public Number castFromLong(long value) {
			throw new UnsupportedOperationException();
		}

		@Override
		public byte[] toByteArray(long value) {
			throw new UnsupportedOperationException();
		}
	},
	BYTE(new Class<?>[]{byte.class, Byte.class}) {
		@Override
		public Number castFromLong(long value) {
			return (byte) value;
		}

		@Override
		public byte[] toByteArray(long value) {
			return new byte[]{(byte) value};
		}
	},
	SHORT(new Class<?>[]{short.class, Short.class}) {
		@Override
		public Number castFromLong(long value) {
			return (short) value;
		}

		@Override
		public byte[] toByteArray(long value) {
			return ByteBuffer.allocate(2).putShort((short) value).array();
		}
	},
	INT(new Class<?>[]{int.class, Integer.class}) {
		@Override
		public Number castFromLong(long value) {
			return (int) value;
		}

		@Override
		public byte[] toByteArray(long value) {
			return ByteBuffer.allocate(4).putInt((int) value).array();
		}
	},
	LONG(new Class<?>[]{long.class, Long.class}) {
		@Override
		public Number castFromLong(long value) {
			return value;
		}

		@Override
		public byte[] toByteArray(long value) {
			return ByteBuffer.allocate(8).putLong((long) value).array();
		}
	};

	/** Primitive and boxing class. */
	private Class<?>[] classes;

	/**
	 * @param classes {@link #classes}
	 */
	private Type(Class<?>[] classes) {
		this.classes = classes;
	}
	
	/**
	 * Determines the type based on class (boxed or unboxed).
	 * 
	 * @param type	Boxed or unboxed class.
	 * @return		Constant representing the type.
	 */
	public static Type getTypeOf(Class<?> type) {
		for (Type primitiveType : Type.values()) {
			for (Class<?> tmpClass : primitiveType.classes) {
				if (tmpClass.equals(type)) {
					return primitiveType;
				}
			}
		}
		
		return null;
	}
	
	/** Returns number converted to appropriate type. */
	public abstract Number	castFromLong(long value);
	
	/** Returns number as array of bytes. */
	public abstract byte[]	toByteArray(long value);
}
